#include "header.h"
#include <GL/gl.h>
#include <GL/glu.h>

void string_to_coef(char* s, int p[]);
void string_to_coef_y(char* s, int p[]);
void drawAxis();
void draw(int x[],int y[]);
void onMouseMotion(SDL_MouseMotionEvent mouse);

SDL_Surface *screen;
double angleX = 0;
double angleY = 0;
double angleZ = 0;
double distance = 2;
int hold = 0;
int x[5];
int y[5];

void initSDL()
{
  if (SDL_Init(SDL_INIT_VIDEO) == -1)
    {
      fprintf(stderr, "Erreur d'init SDL : %s\n", SDL_GetError());
      exit(EXIT_FAILURE);
    }

  screen = SDL_SetVideoMode(640, 640, 32, SDL_OPENGL);

  if (screen == NULL)
    {
      fprintf(stderr, "Erreur de chargement du mode video : %s\n", SDL_GetError());
      exit(EXIT_FAILURE);
    }
  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(70,(double)640/480,1,1000);
  glEnable(GL_DEPTH_TEST);
  
  SDL_WM_SetCaption("Aquila 3D", NULL);
  SDL_EnableKeyRepeat(10,10);
}

void loopy(void)
{
  SDL_Event event;
  int running = 1;

  while(running)
    {
      while(SDL_PollEvent(&event))
	{
	  switch(event.type)
	    {
	    case SDL_KEYDOWN:
	      switch(event.key.keysym.sym)
		{
		case SDLK_UP:
		  angleY++;
		  drawAxis();
		  draw(x,y);
		  break;
		case SDLK_DOWN:
		  angleY--;
		  drawAxis();
                  draw(x,y);
		  break;
		case SDLK_LEFT:
                  angleZ++;
                  drawAxis();
                  draw(x,y);
                  break;
                case SDLK_RIGHT:
                  angleZ--;
                  drawAxis();
                  draw(x,y);
                  break;
		case SDLK_KP_PLUS:
		case SDLK_i:
		  distance--;
		  if(distance < 0.01)
		    distance = 0.1;
		  drawAxis();
		  draw(x,y);
		  break;
		case SDLK_KP_MINUS:
		case SDLK_o:
		  distance++;
		  drawAxis();
		  draw(x,y);
		  break;
		case SDLK_HOME:
		  angleY = 0;
		  angleZ = 0;
		  drawAxis();
		  draw(x,y);
		  break;
		case SDLK_ESCAPE:
		  running = 0;
		default:
		  break;
		}
	      break;
	    case SDL_MOUSEMOTION:
	      if(hold)
		{
		  onMouseMotion(event.motion);
		  drawAxis();
		  draw(x,y);
		}
	      break;
	    case SDL_MOUSEBUTTONUP:
	      hold = 0;
	      break;
	    case SDL_MOUSEBUTTONDOWN:
	      hold = 1;
	      break;
	    case SDL_QUIT:
	      running = 0;
	    }
	}
    }
}

void onMouseMotion(SDL_MouseMotionEvent mouse)
{
      angleZ += mouse.xrel*0.3;
      angleY += mouse.yrel*0.3;
      if (angleY > 90)
	angleY = 90;
      else if (angleY < -90)
	angleY = -90;
}

void drawAxis()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  gluLookAt(distance,3,1,0,0,0,0,0,1);
  glRotated(angleZ,0,0,1);
  glRotated(angleX,1,0,0);
  glRotated(angleY,0,1,0);
  
  glBegin(GL_LINES);
  glColor3ub(0,255,0);
  glVertex3d(-2,0,0);
  glVertex3d(2,0,0);

  glColor3ub(0,0,255);
  glVertex3d(0,-2,0);
  glVertex3d(0,2,0);

  glColor3ub(255,0,0);
  glVertex3d(0,0,2);
  glVertex3d(0,0,-2);
  glEnd();
  
  glFlush();
  SDL_GL_SwapBuffers();
}

float pui(float x, int n)
{
  float res = 1;
  int i;
  if (n < 0)
    {
      return 1/(pui(x,-n));
    }

  for (i = 0; i<n; i++)
    {
      res *= x;
    }
  return res;
}

void draw(int xl[], int yl[])
{
  float step = 0.05;
  float max = 1.0;
  float x = -max;
  float y = -max;

  glBegin(GL_LINES);

  glColor3ub(150,255,25);
  while(y <= max)
    {
      while(x <= max)
	{
	  glVertex3d(x,y,
		     xl[5]*pui(x,5)+xl[4]*pui(x,4)+xl[3]*pui(x,3)+xl[2]*pui(x,2)+xl[1]*x+xl[0]+
		     yl[5]*pui(y,5)+yl[4]*pui(y,4)+yl[3]*pui(y,3)+yl[2]*pui(y,2)+yl[1]*y+yl[0]);
	  x += step;
	  glVertex3d(x,y,
		     xl[5]*pui(x,5)+xl[4]*pui(x,4)+xl[3]*pui(x,3)+xl[2]*pui(x,2)+xl[1]*x+xl[0]+
                     yl[5]*pui(y,5)+yl[4]*pui(y,4)+yl[3]*pui(y,3)+yl[2]*pui(y,2)+yl[1]*y+yl[0]);
	}
      x = -max;
      y += step;
    }

  while(x <= max)
    {
      while(y <= max)
        {
	  glVertex3d(x,y,
		     xl[5]*pui(x,5)+xl[4]*pui(x,4)+xl[3]*pui(x,3)+xl[2]*pui(x,2)+xl[1]*x+xl[0]+
                     yl[5]*pui(y,5)+yl[4]*pui(y,4)+yl[3]*pui(y,3)+yl[2]*pui(y,2)+yl[1]*y+yl[0]);
          y += step;
          glVertex3d(x,y,
		     xl[5]*pui(x,5)+xl[4]*pui(x,4)+xl[3]*pui(x,3)+xl[2]*pui(x,2)+xl[1]*x+xl[0]+
                     yl[5]*pui(y,5)+yl[4]*pui(y,4)+yl[3]*pui(y,3)+yl[2]*pui(y,2)+yl[1]*y+yl[0]);
        }
      y = -max;
      x += step;
    }

  glEnd();

  glFlush();
  SDL_GL_SwapBuffers();
}

void string_to_coef(char* s, int p[])
{
  int i = 0;
  int coef = 0;
  int deg = 0;
  int neg = 0;
  while(s[i] != '\0')
    {
      if (s[i] == '-')
	{
	  neg = 1;
	  i++;
	}
      else if (s[i] == '+')
	{
	  i++;
	}
      if (s[i] == 'x')
	{
	  coef = 1;
	}
      else
	{
	  coef = (s[i] % 48);
	  i++;
	}
      if (s[i] != 'x')
	{
	  deg = 0;
	}
      else
	{
	  i++;
	  if(s[i] == '^')
	    {
	      i++;
	      deg = (s[i++] % 48);
	    }
	  else
	    {
	      deg = 1;
	    }
	}
      if (neg == 1)
	{
	  coef = - coef;
	  neg = 0;
	}
      p[deg] = coef;
    }
}

void string_to_coef_y(char* s, int p[])
{
  int i = 0;
  int coef = 0;
  int deg = 0;
  int neg = 0;
  while(s[i] != '\0')
    {
      if (s[i] == '-')
	{
	  neg = 1;
	  i++;
	}
      else if (s[i] == '+')
	{
	  i++;
	}
      if (s[i] == 'y')
	{
	  coef = 1;
	}
      else
	{
	  coef = (s[i] % 48);
	  i++;
	}
      if (s[i] != 'y')
	{
	  deg = 0;
	}
      else
	{
	  i++;
	  if(s[i] == '^')
	    {
	      i++;
	      deg = (s[i++] % 48);
	    }
	  else
	    {
	      deg = 1;
	    }
	}
      if (neg == 1)
	{
	  coef = - coef;
	  neg = 0;
	}
      p[deg] = coef;
    }
}

int main(int argc, char* argv[])
{
  int i = 0;

  while(i != 6)
    {
      x[i] = 0;
      y[i] = 0;
      i++;
    }

  if(argc == 3)
    {
      string_to_coef(argv[1], x);
      string_to_coef_y(argv[2], y);
      initSDL();
      drawAxis();
      draw(x,y);
      loopy();
      SDL_Quit();
      return 0;
    }
  else
    {
      printf("Erreur : pas de paramètres\n");
      return 1;
    }
}
